/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "imageknife_data_napi.h"
namespace ImageKnifePro {

// 将 imageData 所有属性逐个添加到 JS 对象
napi_value ImageKnifeDataNapi::ConvertToJSObject(napi_env env, const ImageInfo &data)
{
    napi_value result;
    napi_create_object(env, &result); // 创建一个新的 JavaScript 对象
    SetBasicProperties(env, result, data);
    SetTimeInfoProperties(env, result, data.timeInfo);
    SetErrorInfoProperties(env, result, data.errorInfo);
    return result;
}

// 设置基本属性
void ImageKnifeDataNapi::SetBasicProperties(napi_env env, napi_value result, const ImageInfo &data)
{
    // 设置 requestId
    napi_value requestId;
    napi_create_string_utf8(env, data.requestId.c_str(), NAPI_AUTO_LENGTH, &requestId);
    napi_set_named_property(env, result, "requestId", requestId);

    napi_value isMergeRequest;
    napi_create_int32(env, data.isMergedRequest, &isMergeRequest);
    napi_set_named_property(env, result, "isMergedRequest", isMergeRequest);

    // 设置 imageWidth
    napi_value imageWidth;
    napi_create_uint32(env, data.imageWidth, &imageWidth);
    napi_set_named_property(env, result, "imageWidth", imageWidth);

    // 设置 imageHeight
    napi_value imageHeight;
    napi_create_uint32(env, data.imageHeight, &imageHeight);
    napi_set_named_property(env, result, "imageHeight", imageHeight);

    // 设置 bufSize
    napi_value bufSize;
    napi_create_uint32(env, data.bufSize, &bufSize);
    napi_set_named_property(env, result, "bufSize", bufSize);

    // 设置 httpCode
    napi_value httpCode;
    napi_create_uint32(env, data.httpCode, &httpCode);
    napi_set_named_property(env, result, "httpCode", httpCode);
    
    // 设置 type
    napi_value type;
    napi_create_uint32(env, static_cast<int32_t>(data.type), &type);
    napi_set_named_property(env, result, "type", type);
    
    // 设置 frameCount
    napi_value frameCount;
    napi_create_uint32(env, data.frameCount, &frameCount);
    napi_set_named_property(env, result, "frameCount", frameCount);
    
    // 创建 decodeImages 数组
    napi_value decodeImages;
    napi_create_array(env, &decodeImages);

    for (int i = 0; i < data.decodeImages.size(); ++i) {
        // 调用独立的 CreateImageInfo 函数创建 JavaScript 对象并添加到数组中
        napi_value jsImageInfo = CreateImageInfo(env, data.decodeImages[i].contentWidth,
                                                 data.decodeImages[i].contentHeight);
        napi_set_element(env, decodeImages, i, jsImageInfo);
    }

    napi_set_named_property(env, result, "decodeImages", decodeImages);
}

napi_value ImageKnifeDataNapi::CreateImageInfo(napi_env env, int32_t width, int32_t height)
{
    napi_value obj;
    napi_status status = napi_create_object(env, &obj); // 创建对象
    if (status != napi_ok) {
        return nullptr;
    }

    // 设置 contentWidth
    napi_value contentWidth;
    status = napi_create_int32(env, width, &contentWidth);
    status = napi_set_named_property(env, obj, "contentWidth", contentWidth);

    // 设置 contentHeight
    napi_value contentHeight;
    status = napi_create_int32(env, height, &contentHeight);
    status = napi_set_named_property(env, obj, "contentHeight", contentHeight);

    return obj;
}

// 设置 TimeInfo 属性
void ImageKnifeDataNapi::SetTimeInfoProperties(napi_env env, napi_value result, const TimeInfo& timeInfo)
{
    napi_value timeInfoObj;
    napi_create_object(env, &timeInfoObj);

    napi_value executeTime;
    napi_create_int64(env, timeInfo.executeTime, &executeTime);
    napi_set_named_property(env, timeInfoObj, "executeTime", executeTime);

    napi_value requestStartTime;
    napi_create_int64(env, timeInfo.requestStartTime, &requestStartTime);
    napi_set_named_property(env, timeInfoObj, "requestStartTime", requestStartTime);

    napi_value requestEndTime;
    napi_create_int64(env, timeInfo.requestEndTime, &requestEndTime);
    napi_set_named_property(env, timeInfoObj, "requestEndTime", requestEndTime);

    napi_value requestCancelTime;
    napi_create_int64(env, timeInfo.requestCancelTime, &requestCancelTime);
    napi_set_named_property(env, timeInfoObj, "requestCancelTime", requestCancelTime);

    napi_value memoryCheckStartTime;
    napi_create_int64(env, timeInfo.memoryCheckStartTime, &memoryCheckStartTime);
    napi_set_named_property(env, timeInfoObj, "memoryCheckStartTime", memoryCheckStartTime);

    napi_value memoryCheckEndTime;
    napi_create_int64(env, timeInfo.memoryCheckEndTime, &memoryCheckEndTime);
    napi_set_named_property(env, timeInfoObj, "memoryCheckEndTime", memoryCheckEndTime);

    napi_value diskCheckStartTime;
    napi_create_int64(env, timeInfo.diskCheckStartTime, &diskCheckStartTime);
    napi_set_named_property(env, timeInfoObj, "diskCheckStartTime", diskCheckStartTime);

    napi_value diskCheckEndTime;
    napi_create_int64(env, timeInfo.diskCheckEndTime, &diskCheckEndTime);
    napi_set_named_property(env, timeInfoObj, "diskCheckEndTime", diskCheckEndTime);

    napi_value loadImageStartTime;
    napi_create_int64(env, timeInfo.loadImageStartTime, &loadImageStartTime);
    napi_set_named_property(env, timeInfoObj, "loadImageStartTime", loadImageStartTime);

    napi_value loadImageEndTime;
    napi_create_int64(env, timeInfo.loadImageEndTime, &loadImageEndTime);
    napi_set_named_property(env, timeInfoObj, "loadImageEndTime", loadImageEndTime);

    napi_value decodeStartTime;
    napi_create_int64(env, timeInfo.decodeStartTime, &decodeStartTime);
    napi_set_named_property(env, timeInfoObj, "decodeStartTime", decodeStartTime);

    napi_value decodeEndTime;
    napi_create_int64(env, timeInfo.decodeEndTime, &decodeEndTime);
    napi_set_named_property(env, timeInfoObj, "decodeEndTime", decodeEndTime);

    napi_set_named_property(env, result, "timeInfo", timeInfoObj);
}

// 设置 ErrorInfo 属性
void ImageKnifeDataNapi::SetErrorInfoProperties(napi_env env, napi_value result, const ErrorInfo& errorInfo)
{
    napi_value errorInfoObj;
    napi_create_object(env, &errorInfoObj);

    napi_value phase;
    napi_create_string_utf8(env, errorInfo.phase.c_str(), errorInfo.phase.size(), &phase);
    napi_set_named_property(env, errorInfoObj, "phase", phase);

    napi_value code;
    napi_create_int32(env, static_cast<int32_t>(errorInfo.code), &code);
    napi_set_named_property(env, errorInfoObj, "code", code);

    napi_set_named_property(env, result, "errorInfo", errorInfoObj);
}

uint64_t ImageKnifeDataNapi::GetTimestamp()
{
    auto now = std::chrono::system_clock::now();
    auto epoch = now.time_since_epoch();
    auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
    return static_cast<uint64_t>(milliseconds.count());
}

std::unordered_map<LoadPhase, std::string> ImageKnifeDataNapi::phaseToStringMap = {
    {LoadPhase::DISPATCH, "dispatch"},
    {LoadPhase::MEMORY_CACHE, "memoryCache"},
    {LoadPhase::FILE_CACHE, "fileCache"},
    {LoadPhase::LOAD_IMAGE_FETCH, "loadImageFetch"},
    {LoadPhase::DECODE, "decode"},
    {LoadPhase::DOWN_SAMPLE, "downSample"},
    {LoadPhase::TRANSFORM, "transform"}
};
} // namespace ImageKnifePro
